<template>
    <div class="t-chart" v-bind="$attrs">
      <slot></slot>

      <div
        v-show="!formatEmpty"
        class="t-chart-container"
        ref="echartRef"
        
        />
      <slot v-if="formatEmpty" name="empty">
        <!-- <el-empty v-bind="$attrs" :description="description" /> -->
        <Empty description="没有找到相关数据" /> 
      </slot>
    </div>
  </template>
  
  <script setup  name="TChart">
  import Empty from './Empty.vue'
  import {
    onMounted,
    getCurrentInstance,
    ref,
    watch,
    nextTick,
    onBeforeUnmount,
    markRaw,
    useAttrs,
  } from 'vue'
import * as echarts from 'echarts'

//   中文网  https://vueuse.nodejs.cn/core/useResizeObserver/
// 解释 ：https://blog.51cto.com/u_15715491/11396501
  import { useResizeObserver } from '@vueuse/core'
  import { debounce, toLine } from '../utils'
  import { computed } from 'vue'
  // import china from "@/assets/json/china.json"
  const { proxy } = getCurrentInstance()
  // 接收传入的一些属性
  // options是当前echarts的配置项 
    //  ifMap 是判断如果是地图的话.单独需要设置地图的registerMap注册
    // theme 修改主题
    // isEmpty 判断数据没有的情况展示插件默认内容(暂无数据)
  const props = defineProps({
    options: {
      type: Object,
      default: () => ({}),
    },
    ifMap:{
      type:Boolean,
      default:false
    },
    theme: {
      type: String,
      default: '',
    },
    isEmpty: {
      type: [Boolean, Function],
      default: false,
    },
    description: {
      type: String,
      default: '暂无数据',
    },
  })
  
  const echartRef = ref()
  const chart = ref()
  const emits = defineEmits()
//   console.log("useAttrs()",useAttrs())
//   useAttrs 包括了传递给当前组件的所有属性以及事件组成的对象，其中包含当前组件的透传 attributes。不包含被defineProps接收的
  const events = Object.entries(useAttrs())
  console.log("events",events)
  
  // 图表初始化 :初始化一个echarts实例,有主题色传入主题色 
  // 是地图就注册一下
  // 每次调用初始化都触发渲染 setOption
  // 通过循环把echarts 传入进来的事件.又派发出去了.让在父组件里面点击echart也能拿到事件
  const renderChart = async() => {
    chart.value = markRaw(proxy.$echarts.init(echartRef.value, props.theme))
    if(props.ifMap){
      console.log("看看中国的地图数据",)
      const json = await import(`@/assets/json/${props.options.geo.map}.json`)
      echarts.registerMap(props.options.geo.map, json.default)
    }
    setOption(props.options)
    // 返回chart实例
    emits('chart', chart.value)
  
    // 监听图表事件
    events.forEach(([key, value]) => {
      if (key.startsWith('on') && !key.startsWith('onChart')) {
        const on = toLine(key).substring(3)
        // onClick  on_click
        chart.value.on(on, (...args) => emits(on, ...args))
      }
    })
  
    // 监听元素变化 用的vueHooks库的方法
    useResizeObserver(echartRef.value, resizeChart)
    // 如果不想用vueuse，可以使用下边的方法代替，但组件使用v-show时，不会触发resize事件
    // window.addEventListener('resize', resizeChart)
  }
  
  // 重绘图表函数
  const resizeChart = debounce(
    () => {
      chart.value?.resize()   //echarts实例调用自己的resize方法.就能适配当前容器大小
    },
    300,
    true
  )
  
  // 设置图表函数
  const setOption = debounce(
    async (data) => {
      if (!chart.value) return
      chart.value.setOption(data, true, true) //重新绘制图表了.就需要重新设置大小
      await nextTick()
      resizeChart()
    },
    300,
    true
  )
  
  const formatEmpty = computed(() => {
    // 计算属性 当依赖性 isEmpty options
    if (typeof props.isEmpty === 'function') {
        // 父组件传递进来的这个属性是一个函数
      return props.isEmpty(props.options)
    }
    return props.isEmpty
  })
  // 只要options改变(数据请求了.点击了按钮改变了数据.都会触发监听)
  watch(
    () => props.options,
    async (nw) => {
      console.log("数据变化后这里变了吗",nw)
      await nextTick()
      setOption(nw)
    },
    { deep: true }
  )
  // 监听主题变化
  watch(
    () => props.theme,
    async () => {
      chart.value.dispose() //销毁
      renderChart()
    }
  )
  // 页面加载就会调用echats渲染
  onMounted(() => {
    renderChart()
  })
  // 页面销毁 销毁echarts  性能优化
  onBeforeUnmount(() => {
    // 取消监听
    // window.removeEventListener('resize', resizeChart)
    // 销毁echarts实例
    chart.value.dispose()
    chart.value = null
  })
  </script>
  
  <style lang="scss" scoped>
  .t-chart {
    position: relative;
    width: 100%;
    height: 100%;
    &-container {
      width: 100%;
      height: 100%;
    }
  }
  </style>
  